const fs = require('fs');
const path = require('path');
/**
 *
 * @param dir
 * @param callback
 */
function readFileList(dir,callback) {
  fs.readdir(dir, (err, files) => {
    new Promise((resolve,reject)=>{
      !err ? resolve() : reject(err);
    }).then(
        ()=>{
          let filesList = [];
          files.forEach((item) => {
            let fullPath = dir[dir.length - 1] === '/' ? `${dir}${item}` : `${dir}/${item}`;
            filesList.push(fullPath);
          })
          callback(null,filesList);
        }
        ,(error)=>{
          callback(error,null);
        }
    ).catch((e)=>{
      throw new Error(e);
    })
  });
}

/**
 *
 * @param {string} path
 * @param {Function} callback
 */
function readFile(path,callback){
  fs.readFile(path,callback);
}
function readFileListSync(dir, filesList = []) {
  const files = fs.readdirSync(dir);
  files.forEach((item) => {
    let fullPath = dir[dir.length - 1] === '/' ? `${dir}${item}` : `${dir}/${item}`;
    filesList.push(fullPath);
  });
  return filesList;
}

/**
 * check path
 * @param path
 * @param callback
 */
function checkPath(path, callback) {
  /*fs.access(path, fs.constants.F_OK, (err) => {
    callback(!err);
  })*/
  fs.stat(path,(error,stats)=>{
    new Promise((resolve,reject)=>{
      !error ? resolve(stats) : reject(error);
    }).then(
        (stats)=>{
          callback(false,stats.isFile())
        }
        ,(error)=>{
          callback(error,null);
        }
    ).catch((error)=>{
      callback(error,null);
    })
  })
}

/**
 *
 * @param path
 */
function readStream(path){
  return fs.createReadStream(path);
}


/**
 * write a file
 * @param path
 * @param information
 * @param type
 */
function write(path, information, type) {
  fs.writeFile(path, information, {flag: type || "a"}, (err) => {
    new Promise((resolve,reject)=>{
      !err ? resolve() : reject();
    }).then(
        ()=>{
          arguments[-1](1);
        }
        ,()=>{
          arguments[-1](0);
        }
    )
  });
}

/**
 *
 * @param path
 * @param buffer
 * @param callback
 */
const writeFileRecursive = function (path, buffer, callback) {
  let lastPath = path.substring(0, path.lastIndexOf("/"));
  fs.mkdir(lastPath, {recursive: true}, (err) => {
    if (err) return callback(err);
    fs.writeFile(path, buffer, function (err) {
      if (err) return callback(err);
      return callback(undefined);
    });
  });
};

let deleteFolder = function(path) {
  let files = [];
  if( fs.existsSync(path) ) {
    files = fs.readdirSync(path);
    files.forEach(function(file){
      let curPath = path + "/" + file;
      if(fs.statSync(curPath).isDirectory()) { // recurse
        deleteFolder(curPath);
      } else { // delete file
        fs.unlinkSync(curPath);
      }
    });
    fs.rmdirSync(path);
  }
};

function mkdirsSync(dirname) {
  if (fs.existsSync(dirname)) {
    return true;
  } else {
    if (mkdirsSync(path.dirname(dirname))) {
      fs.mkdirSync(dirname);
      return true;
    }
  }
}

function _copy(src, dist) {
  let paths = fs.readdirSync(src);
  paths.forEach(function(p) {
    let _src = src + '/' +p;
    let _dist = dist + '/' +p;
    let stat = fs.statSync(_src);
    if(stat.isFile()) {
      fs.writeFileSync(_dist, fs.readFileSync(_src));
    } else if(stat.isDirectory()) {
      copyDir(_src, _dist)
    }
  })
}

function copyDir(src,dist){
  let b = fs.existsSync(dist);
  if(!b){
    mkdirsSync(dist);
  }
  _copy(src,dist);
}

function stat(path,callback){
  fs.stat(path,callback);
}

function readAllFileSync(path){
  let files = readFileListSync(path);
  for(let i of files){
    let bool = fs.statSync(i).isDirectory();
    bool ? /\w+\.\w+$/.test(i.split('/')[i.split('/').length-1]) !== true ? files.push(...readAllFile(i)) : 0 : 0;
  }
  return files
}

module.exports = {
  readFileList : readFileList,
  readFileListSync : readFileListSync,
  readFile : readFile,
  readStream:readStream,
  checkPath:checkPath,
  write:write,
  writeFileRecursive:writeFileRecursive,
  deleteFolder : deleteFolder,
  copyDir : copyDir,
  stat : stat,
  readAllFileSync : readAllFileSync
}